#include "connection.h"

/**
* Create a server connection that will allow you to send and receive data to the server.
*
* @param string address
* @param int port
*/
Connection::Connection(std::string address, std::string port)
{
	this->address	= address;
	this->port	= port;
	this->conn	= INVALID_SOCKET;
	this->status	= CLOSED;
}

/**
* Open a connection to the server.
*
* @return bool
*/
bool Connection::open()
{
	struct addrinfo *addr, *ptr, hints;

#ifdef _WIN32
	ZeroMemory(&hints, sizeof(hints));
	hints.ai_family = AF_UNSPEC;
#elif
	memset(&hints, 0, sizeof(hints));
	hints.ai_family = PF_UNSPEC;
#endif

	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = IPPROTO_TCP;

	if (getaddrinfo(this->address.c_str(), this->port.c_str(), &hints, &addr) != 0)
	{
		return false;
	}

	for (ptr = addr; ptr != NULL ;ptr=ptr->ai_next)
	{
		this->conn = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);

		if (this->conn == INVALID_SOCKET)
		{
			this->close();
			return false;
		}

		if (connect(this->conn, ptr->ai_addr, (int)ptr->ai_addrlen) == SOCKET_ERROR)
		{
			this->close();
			return false;;
		}

		break;
	}

	freeaddrinfo(addr);

	this->status = OPEN;

	return true;
}

/**
* Closes the connection.
*/
void Connection::close()
{
	closesocket(this->conn);

	this->conn	= INVALID_SOCKET;
	this->status	= CLOSED;
}

/**
* Check if the connection is open.
*/
bool Connection::isOpen()
{
	if(this->conn == INVALID_SOCKET) {
		return false;
	}

	// TODO: Perhaps add a Ping/Pong in order to find out if the server is responding.

	return true;
}

/**
* Send data to the server.
*
* @param string message
*/
void Connection::send(std::string message)
{
	message += "\r\n";

	this->status = SENDING;

	::send(this->conn, message.c_str(), strlen(message.c_str()), 0);

	this->status = OPEN;
}

/**
* Send data to the server.
*
* @param string message
* @param int flags
*/
void Connection::send(std::string message, int flags)
{
	this->status = SENDING;

	::send(this->conn, message.c_str(), strlen(message.c_str()), flags);

	this->status = OPEN;
}

/**
* Receive data from the server.
*
* @note Places the received data into the buffer.
* @note Returns the length of the received data.
*
* @param int length
* @param char* buffer
*
* @return int
*/
int Connection::receive(int length, char *buffer)
{
	this->status = RECEIVING;

	int received = recv(this->conn, buffer, length, 0);

	if (received > 0)
	{
		buffer[received] = '\0';
	}

	this->status = OPEN;

	return received;
}

/**
* Receive data from the server.
*
* @note Places the received data into the buffer.
* @note Returns the length of the received data.
*
* @param int length
* @param char* buffer
* @param int flags
*
* @return int
*/
int Connection::receive(int length, char *buffer, int flags)
{
	this->status = RECEIVING;

	int received = recv(this->conn, buffer, length, flags);

	this->status = OPEN;

	return received;
}

SOCKET Connection::getSocket()
{
	return this->conn;
}